package testApplets;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Vector;


import peasy.PeasyCam;
import processing.core.PApplet;
import simpleGeom.AbstractFace;
import simpleGeom.BasicMesh;
import simpleGeom.Bounds3D;
import simpleGeom.Box3D;
import simpleGeom.Face3D;
import simpleGeom.HasPos3D;
import simpleGeom.HasPos3DXComparator;
import simpleGeom.HasPos3DYComparator;
import simpleGeom.HasPos3DZComparator;
import simpleGeom.Mesh;
import simpleGeom.MeshFace;
import simpleGeom.MeshNode;
import simpleGeom.Node;
import simpleGeom.SimpleTriangle;
import simpleGeom.Vec3D;

public class ImplatConeMergeVertices extends PApplet  {
	public String folderPath="/Users/caad/Desktop/Grotto - First Half V/03_scaled/";
	ArrayList<AbstractFace>faces=new ArrayList<AbstractFace>();
	Box3D box;
	int nSegments=32;// durch 4 teilbar
	float coneOffset=-5;
	float coneHeight=30;
	float coneRadius=30;
	float dim=32;
	float yTol=0.01f;
	Mesh mesh;
	// delete Faces in one Box.
	// remove unused Vertices
	// create Implantation
	// merge the vertices...
	// units mm
	int[][]level0Up;
	int[][]level1Up;
	int[][]level2Up;
	int[][]level3Up;
	int[][]level4Up;
	int[][]level5Up;
	int[][]level6Up;
	int[][]level7Up;
	int[][]level0horizontal;//0 nix, 1 links -1 rechts, 2, -2 oben unten
	
	public void setup(){
		setDetails();
		/*processMesh(folderPath+"v9_0_0.obj");
		processMesh(folderPath+"v9_0_1.obj");
		processMesh(folderPath+"v9_0_2.obj");
		processMesh(folderPath+"v9_0_3.obj");
		processMesh(folderPath+"v9_0_4.obj");*/
		//processMesh(folderPath+"v5_2_0.obj");
		//doConesLevel(folderPath+"layer4part3date6_16_20sel.obj",level3Up,level4Up);
		//doConesLevel(folderPath+"layer6part0date6_24_16sel.obj",level4Up,level5Up);
		//doConesLevel(folderPath+"layer6part1date6_24_22sel.obj",level5Up,level6Up);
		doConesLevel(folderPath+"layer7part3date7_3_12sel.obj",level6Up,level7Up);
		//doConesLevel(folderPath+"layer7part4date7_3_11sel.obj",level6Up,level7Up);
		//doConesLevel(folderPath+"layer6part2date6_24_22sel.obj",level5Up,level6Up);
		//doConesLevel(folderPath+"layer6part3date6_24_22sel.obj",level5Up,level6Up);
		//doConesLevel(folderPath+"layer6part2date6_24_16sel.obj",level4Up,level5Up);
		//doConesLevel(folderPath+"layer6part3date6_24_16sel.obj",level4Up,level5Up);
		//doConesLevel(folderPath+"layer4part3date6_19_10sel.obj",level3Up,level4Up);
		//doConesLevel(folderPath+"layer4part1date6_19_10.obj",level3Up,level4Up);
		//doConesLevel(folderPath+"layer4part3date6_16_18sel.obj",level3Up,level4Up);
		//doConesLevel(folderPath+"layer4part4date6_16_18sel.obj",level3Up,level4Up);
		
		
		//processMesh(folderPath+"v6_2_3.obj");
		//processMesh(folderPath+"v3_1_2.obj");
		//processMesh(folderPath+"v3_1_3.obj");
		exit();
	}
	public String timeStamp(){
		return "date"+month()+"_"+day()+"_"+hour();
	}
	public void processMesh(String path){
		mesh=new Mesh(path);
		//doConesLevel1(mesh,mesh.getBounds());
		doConesLevel2(mesh,mesh.getBounds());
		path=path.replace(".obj", "");
		mesh.saveMesh(path+"detail.obj");
	}
	
	public void setDetails(){
		level0Up=new int[7][7];
		level0Up[0]=new int[]{0,1,1,1,1,1,1};
		level0Up[1]=new int[]{0,1,1,1,1,1,1};
		level0Up[2]=new int[]{0,0,1,1,1,1,1};
		level0Up[3]=new int[]{0,0,0,1,1,1,1};
		level0Up[4]=new int[]{0,0,0,0,0,0,1};
		level0Up[5]=new int[]{0,0,0,0,0,0,1};
		level0Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level0horizontal=new int[7][7];
		level0horizontal[0]=new int[]{0,0,0,0,0,0,0};
		level0horizontal[1]=new int[]{0,2,2,0,2,0,0};
		level0horizontal[2]=new int[]{0,0,0,3,0,3,0};
		level0horizontal[3]=new int[]{0,0,0,3,0,3,0};
		level0horizontal[4]=new int[]{0,0,0,3,0,0,0};
		level0horizontal[5]=new int[]{0,0,0,3,0,3,0};
		level0horizontal[6]=new int[]{0,0,0,0,0,0,0};
		
		
		level1Up=new int[7][7];
		level1Up[0]=new int[]{0,0,0,1,1,1,1};
		level1Up[1]=new int[]{0,0,0,1,1,1,1};
		level1Up[2]=new int[]{0,0,0,1,1,1,1};
		level1Up[3]=new int[]{0,0,0,1,1,1,1};
		level1Up[4]=new int[]{0,0,0,0,0,0,1};
		level1Up[5]=new int[]{0,0,0,0,0,0,1};
		level1Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level2Up=new int[7][7];
		level2Up[0]=new int[]{0,0,0,0,1,1,1};
		level2Up[1]=new int[]{0,0,0,1,1,1,1};
		level2Up[2]=new int[]{0,0,0,1,1,1,1};
		level2Up[3]=new int[]{0,0,0,0,1,1,1};
		level2Up[4]=new int[]{0,0,0,0,0,0,1};
		level2Up[5]=new int[]{0,0,0,0,0,0,1};
		level2Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level3Up=new int[7][7];
		level3Up[0]=new int[]{0,0,0,0,1,1,1};
		level3Up[1]=new int[]{0,0,0,0,0,1,1};
		level3Up[2]=new int[]{0,0,0,0,0,0,1};
		level3Up[3]=new int[]{0,0,0,0,0,1,1};
		level3Up[4]=new int[]{0,0,0,0,0,0,1};
		level3Up[5]=new int[]{0,0,0,0,0,0,1};
		level3Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level4Up=new int[7][7];
		
		level4Up[0]=new int[]{0,0,0,0,1,1,1};
		level4Up[1]=new int[]{0,0,0,0,0,1,1};
		level4Up[2]=new int[]{0,0,0,0,0,0,1};
		level4Up[3]=new int[]{0,0,0,0,0,1,1};
		level4Up[4]=new int[]{0,0,0,0,0,0,1};
		level4Up[5]=new int[]{0,0,0,0,0,0,1};
		level4Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level5Up=new int[7][7];
		
		level5Up[0]=new int[]{0,0,0,0,1,1,1};
		level5Up[1]=new int[]{0,0,0,0,0,1,0};
		level5Up[2]=new int[]{0,0,0,0,0,0,1};
		level5Up[3]=new int[]{0,0,0,0,0,1,0};
		level5Up[4]=new int[]{0,0,0,0,0,0,1};
		level5Up[5]=new int[]{0,0,0,0,0,0,0};
		level5Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level6Up=new int[7][7];
		
		level6Up[0]=new int[]{0,0,0,0,0,0,1};
		level6Up[1]=new int[]{0,0,0,0,0,0,0};
		level6Up[2]=new int[]{0,0,1,0,0,0,1};
		level6Up[3]=new int[]{0,0,0,1,0,1,0};
		level6Up[4]=new int[]{0,0,0,0,0,1,0};
		level6Up[5]=new int[]{0,0,0,0,0,0,0};
		level6Up[6]=new int[]{0,0,0,0,0,0,0};
		
		level7Up=new int[7][7];
		level7Up[0]=new int[]{0,0,0,0,0,0,0};
		level7Up[1]=new int[]{0,0,0,0,0,0,0};
		level7Up[2]=new int[]{0,0,0,0,0,0,0};
		level7Up[3]=new int[]{0,0,0,0,0,0,0};
		level7Up[4]=new int[]{0,0,0,0,0,0,0};
		level7Up[5]=new int[]{0,0,0,0,0,0,0};
		level7Up[6]=new int[]{0,0,0,0,0,0,0};
	}
	float[]segStringX=new float[]{ 0.5f,250.5f,500.5f,750.5f,1000.5f,1250.5f,1500.5f};
	float[]segStringZ=new float[]{ -1532.5f,-1277,-1021.5f,-766,-510.5f,-255,0.5f};

	public void doCones(Mesh mesh,Bounds3D b3d){
		
		println("bounds: "+b3d);
		
		float y1=b3d.y1;
		float y2=b3d.y2;
		float coneGap=1;
		for (int x=0;x<segStringX.length;x++){
			for (int z=0;z<segStringZ.length;z++){
				float xF1=(int)(segStringX[x]-70-10)+0.5f;
				float xF2=xF1+70;
				float zF1=(int)segStringZ[z]+10+0.5f;
				float zF2=zF1+70;
				float yF1=b3d.y2-10;
				float yF2=b3d.y2+10;
				float os=0.9f;
				Box3D boxY=new Box3D(xF1-os,yF1,zF1-os,xF2+os,yF2,zF2+os);
				
				if (level0Up[z][x]==1&&b3d.isOverlap(boxY)){
					//nach aussen oben
					println("implement Y");
					delete(mesh,boxY);
					Mesh coneMesh=getConeWithPlate(70,1,coneRadius-coneGap,coneHeight-coneGap);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y2, zF1);
					implement(mesh,boxY,coneMesh);
					//mirroring
					if(x==6&&(z==5||z==4)){
						 boxY=new Box3D(xF1-os,yF1,-1*(zF2+os),xF2+os,yF2,-1*(zF1-os));
						 delete(mesh,boxY);
						 coneMesh=getConeWithPlate(70,1,coneRadius-coneGap,coneHeight-coneGap);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y2, -zF2);
						implement(mesh,boxY,coneMesh);
					}
				}
				
				
				 xF1=(int)(segStringX[x]-35)+0.5f;
				 xF2=xF1+70;
				 zF1=(int)segStringZ[z]-10;
				 zF2=zF1+20;
				 yF1=b3d.y1+150.5f;
				 yF2=yF1+70;
				 Box3D boxZ=new Box3D(xF1-os,yF1-os,zF1,xF2+os,yF2+os,zF2);
				 
				 if (level0horizontal[z][x]==2&&b3d.isOverlap(boxZ)){
					 println("implement Z");
					delete(mesh,boxZ);
					Mesh coneMesh;
					if (b3d.getCenterZ()>boxZ.getCenterZ()){
						//nach innen oberer rand
						coneMesh=getConeWithPlate(70,1,coneRadius,coneHeight);
						coneMesh.translate(xF1, yF1, b3d.z1);
						implement(mesh,boxZ,coneMesh);
						
					}
					else{
						//nach aussen unterer rand
						coneMesh=getConeWithPlate(70,1,coneRadius-coneGap,(coneHeight-coneGap));
						coneMesh.translate(xF1, yF1, b3d.z2);
						coneMesh.invertFaces();
						implement(mesh,boxZ,coneMesh);
					}
				
					
				}
				 
				 xF1=segStringX[x]-10;
				 xF2=xF1+20;
				 zF1=(int)(segStringZ[z]-35)+0.5f;
				 zF2=zF1+70;
				 yF1=b3d.y1+150.5f;
				 yF2=yF1+70;
				 Box3D boxX=new Box3D(xF1,yF1-os,zF1-os,xF2,yF2+os,zF2+os);
				if (level0horizontal[z][x] == 3 && b3d.isOverlap(boxX)) {
					println("implement X");
					delete(mesh, boxX);
					Mesh coneMesh ;
					if (b3d.getCenterX()>boxX.getCenterX()){
						//nach aussen, linker rand
						coneMesh=getConeWithPlate(70,1,coneRadius-coneGap,-(coneHeight-coneGap));
						coneMesh.XToZ();
						coneMesh.translate(b3d.x1, yF1, zF1);
						coneMesh.invertFaces();
						implement(mesh, boxX, coneMesh);
						
						if(z==5&&x==5){
							boxX=new Box3D(xF1,yF1-os,-1*(zF2+os),xF2,yF2+os,-1*(zF1-os));
							 delete(mesh,boxX);
							 coneMesh=getConeWithPlate(70,1,coneRadius-coneGap,-(coneHeight-coneGap));
							coneMesh.XToZ();
							coneMesh.translate(b3d.x1, yF1, -zF2);
							coneMesh.invertFaces();
							implement(mesh,boxX,coneMesh);
						}
					}
					else{
						//nach innen, rechter rand
						coneMesh=getConeWithPlate(70,1,coneRadius,-coneHeight);
						coneMesh.XToZ();
						coneMesh.translate(b3d.x2, yF1, zF1);
						implement(mesh, boxX, coneMesh);
					}
					
				}
			}
		}
	}

	public void doConesLevel1(Mesh mesh, Bounds3D b3d) {

		println("bounds: " + b3d);

		float y1 = b3d.y1;
		float y2 = b3d.y2;
		float coneGap = 1;
		for (int x = 0; x < segStringX.length; x++) {
			for (int z = 0; z < segStringZ.length; z++) {
				float xF1 = (int) (segStringX[x] - 70 - 10) + 0.5f;
				float xF2 = xF1 + 70;
				float zF1 = (int) segStringZ[z] + 10 + 0.5f;
				float zF2 = zF1 + 70;
				float yF1 = b3d.y2 - 10;
				float yF2 = b3d.y2 + 10;
				float os = 0.9f;
				Box3D boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2,
						zF2 + os);

				if (level1Up[z][x] == 1 && b3d.isOverlap(boxY)) {
					// nach aussen oben
					println("implement Y");
					delete(mesh, boxY);
					Mesh coneMesh = getConeWithPlate(70, 1, coneRadius
							- coneGap, coneHeight - coneGap);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y2, zF1);
					coneMesh.invertFaces();
					implement(mesh, boxY, coneMesh);
					// mirroring
					if (x == 6 && (z == 5 || z == 4)) {
						boxY = new Box3D(xF1 - os, yF1, -1 * (zF2 + os), xF2
								+ os, yF2, -1 * (zF1 - os));
						delete(mesh, boxY);
						coneMesh = getConeWithPlate(70, 1,
								coneRadius - coneGap, coneHeight - coneGap);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y2, -zF2);
						coneMesh.invertFaces();
						implement(mesh, boxY, coneMesh);
					}
				}

				xF1 = (int) (segStringX[x] - 70 - 10) + 0.5f;
				xF2 = xF1 + 70;
				zF1 = (int) segStringZ[z] + 10 + 0.5f;
				zF2 = zF1 + 70;
				yF1 = b3d.y1 - 10;
				yF2 = b3d.y1 + 10;
				os = 0.9f;
				boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2, zF2
						+ os);
				if (level0Up[z][x] == 1 && b3d.isOverlap(boxY)) {
					// nach aussen oben
					println("implement Y");
					delete(mesh, boxY);
					Mesh coneMesh = getConeWithPlate(70, 1, coneRadius,
							coneHeight);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y1, zF1);
					implement(mesh, boxY, coneMesh);
					// mirroring
					if (x == 6 && (z == 5 || z == 4)) {
						boxY = new Box3D(xF1 - os, yF1, -1 * (zF2 + os), xF2
								+ os, yF2, -1 * (zF1 - os));
						delete(mesh, boxY);
						coneMesh = getConeWithPlate(70, 1, coneRadius,
								coneHeight);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y1, -zF2);
						implement(mesh, boxY, coneMesh);
					}
				}

			}
		}
	}
	float coneGap = 1;
	public void doConesLevel(String path,int[][] level0Up,int[][] level1Up) {
		mesh=new Mesh(path);
		Box3D b3d=mesh.getBounds();
		//b3d.y2=2408;
		println("bounds: " + b3d);

		float y1 = b3d.y1;
		float y2 = b3d.y2;
		
		
		/*
		if (iLayer==6){
			zF1=zSegs[1]-dPropf;
			xF1=xSegs[1];
			this.addBox(xF1-dPropf,y1f, zF1, xF1+dPropf, y2f, zF1+dPropf, grid, depth, by1,bd);
			xF1=xSegs[2];
			this.addBox(xF1-dPropf,y1f, zF1, xF1+dPropf, y2f, zF1+dPropf, grid, depth, by1,bd);
		}
		*/
		//insertConeUp(250-50,y2,segStringZ[1],b3d);
		//insertConeUp(400-50,y2,segStringZ[1],b3d);
		//insertConeDown(250-50,y1,segStringZ[1],b3d);
		//insertConeDown(400-50,y1,segStringZ[1],b3d);
		
		for (int x = 0; x < segStringX.length; x++) {
			for (int z = 0; z < segStringZ.length; z++) {
				float xF1 = (int) (segStringX[x] - 70 - 10) + 0.5f;
				float xF2 = xF1 + 70;
				float zF1 = (int) segStringZ[z] + 10 + 0.5f;
				float zF2 = zF1 + 70;
				float yF1 = b3d.y2 - 10;
				float yF2 = b3d.y2 + 10;
				float os = 0.9f;
				Box3D boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2,
						zF2 + os);

				if (level1Up[z][x] == 1 && b3d.isOverlap(boxY)) {
					// nach aussen oben
					println("implement Y");
					delete(mesh, boxY);
					Mesh coneMesh = getConeWithPlate(70, 1, coneRadius
							- coneGap, coneHeight - coneGap);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y2, zF1);
					coneMesh.invertFaces();
					implement(mesh, boxY, coneMesh);
					// mirroring
					if ((x == 6 ||x==4||x==5)&& (z == 5 || z == 4)) {
						println("mirrored");
						boxY = new Box3D(xF1 - os, yF1, -1 * (zF2 + os), xF2
								+ os, yF2, -1 * (zF1 - os));
						delete(mesh, boxY);
						coneMesh = getConeWithPlate(70, 1,
								coneRadius - coneGap, coneHeight - coneGap);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y2, -zF2);
						coneMesh.invertFaces();
						implement(mesh, boxY, coneMesh);
					}
				}
				

				xF1 = (int) (segStringX[x] - 70 - 10) + 0.5f;
				xF2 = xF1 + 70;
				zF1 = (int) segStringZ[z] + 10 + 0.5f;
				zF2 = zF1 + 70;
				yF1 = b3d.y1 - 10;
				yF2 = b3d.y1 + 10;
				os = 0.9f;
				boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2, zF2
						+ os);
				if (level0Up[z][x] == 1 && b3d.isOverlap(boxY)) {
					// nach aussen oben
					println("implement Y");
					delete(mesh, boxY);
					Mesh coneMesh = getConeWithPlate(70, 1, coneRadius,
							coneHeight);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y1, zF1);
					implement(mesh, boxY, coneMesh);
					// mirroring
					if ((x == 6 ||x==4||x==5)&& (z == 5 || z == 4)) {
						boxY = new Box3D(xF1 - os, yF1, -1 * (zF2 + os), xF2
								+ os, yF2, -1 * (zF1 - os));
						delete(mesh, boxY);
						coneMesh = getConeWithPlate(70, 1, coneRadius,
								coneHeight);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y1, -zF2);
						implement(mesh, boxY, coneMesh);
					}
				}

			}
		}
		path=path.replace(".obj", "");
		mesh.saveMesh(path+"detail.obj");
	}
	public void insertConeUp(float x,float y,float z,Box3D b3d){
		float xF1=(int) (x + 10) + 0.5f;
		float xF2 = xF1 + 70;
		float zF1=(int) (z - 70- 10) + 0.5f;
		float zF2 = zF1 + 70;
		float yF1 = y - 10;
		float yF2 = y + 20;
		float os = 0.9f;
		Box3D boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2,
				zF2 + os);
		if ( b3d.isOverlap(boxY)) {
			// nach aussen oben
			println("implement Y");
			delete(mesh, boxY);
			Mesh coneMesh = getConeWithPlate(70, 1, coneRadius
					- coneGap, coneHeight - coneGap);
			coneMesh.YToZ();
			coneMesh.translate(xF1, b3d.y2, zF1);
			coneMesh.invertFaces();
			implement(mesh, boxY, coneMesh);
			// mirroring
		}
	}
	
	public void insertConeDown(float x,float y,float z,Box3D b3d){
		float xF1=(int) (x + 10) + 0.5f;
		float xF2 = xF1 + 70;
		float zF1=(int) (z - 70- 10) + 0.5f;
		float zF2 = zF1 + 70;
		float yF1 = y - 10;
		float yF2 = y + 20;
		float os = 0.9f;
		Box3D boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2,
				zF2 + os);
		if ( b3d.isOverlap(boxY)) {
			// nach aussen oben
			println("implement Y");
			delete(mesh, boxY);
			Mesh coneMesh = getConeWithPlate(70, 1, coneRadius
					, coneHeight );
			
			coneMesh.YToZ();
			coneMesh.translate(xF1, b3d.y1, zF1);
			implement(mesh, boxY, coneMesh);
			// mirroring
		}
	}
	
	
	public void doConesLevel2(Mesh mesh, Bounds3D b3d) {

		println("bounds: " + b3d);

		float y1 = b3d.y1;
		float y2 = b3d.y2;
		float coneGap = 1;
		for (int x = 0; x < segStringX.length; x++) {
			for (int z = 0; z < segStringZ.length; z++) {
				float xF1 = (int) (segStringX[x] - 70 - 10) + 0.5f;
				float xF2 = xF1 + 70;
				float zF1 = (int) segStringZ[z] + 10 + 0.5f;
				float zF2 = zF1 + 70;
				float yF1 = b3d.y2 - 10;
				float yF2 = b3d.y2 + 10;
				float os = 0.9f;
				Box3D boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2,
						zF2 + os);

				if (level2Up[z][x] == 1 && b3d.isOverlap(boxY)) {
					// nach aussen oben
					println("implement Y");
					delete(mesh, boxY);
					Mesh coneMesh = getConeWithPlate(70, 1, coneRadius
							- coneGap, coneHeight - coneGap);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y2, zF1);
					coneMesh.invertFaces();
					implement(mesh, boxY, coneMesh);
					// mirroring
					if (x == 6 && (z == 5 || z == 4)) {
						boxY = new Box3D(xF1 - os, yF1, -1 * (zF2 + os), xF2
								+ os, yF2, -1 * (zF1 - os));
						delete(mesh, boxY);
						coneMesh = getConeWithPlate(70, 1,
								coneRadius - coneGap, coneHeight - coneGap);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y2, -zF2);
						coneMesh.invertFaces();
						implement(mesh, boxY, coneMesh);
					}
				}

				xF1 = (int) (segStringX[x] - 70 - 10) + 0.5f;
				xF2 = xF1 + 70;
				zF1 = (int) segStringZ[z] + 10 + 0.5f;
				zF2 = zF1 + 70;
				yF1 = b3d.y1 - 10;
				yF2 = b3d.y1 + 10;
				os = 0.9f;
				boxY = new Box3D(xF1 - os, yF1, zF1 - os, xF2 + os, yF2, zF2
						+ os);
				if (level1Up[z][x] == 1 && b3d.isOverlap(boxY)) {
					// nach aussen oben
					println("implement Y");
					delete(mesh, boxY);
					Mesh coneMesh = getConeWithPlate(70, 1, coneRadius,
							coneHeight);
					coneMesh.YToZ();
					coneMesh.translate(xF1, b3d.y1, zF1);
					implement(mesh, boxY, coneMesh);
					// mirroring
					if (x == 6 && (z == 5 || z == 4)) {
						boxY = new Box3D(xF1 - os, yF1, -1 * (zF2 + os), xF2
								+ os, yF2, -1 * (zF1 - os));
						delete(mesh, boxY);
						coneMesh = getConeWithPlate(70, 1, coneRadius,
								coneHeight);
						coneMesh.YToZ();
						coneMesh.translate(xF1, b3d.y1, -zF2);
						implement(mesh, boxY, coneMesh);
					}
				}
			}
		}
	}
	public void delete(Mesh mesh,Box3D b3d){
		boolean[] delete=new boolean[mesh.getNFaces()];
		int nFaces=0;
		ArrayList<MeshFace>newFaces=new ArrayList<MeshFace>();
		
		for (int i=0;i<mesh.getNFaces();i++){
			MeshFace face=mesh.getFace(i);
			boolean inside=true;
			for (int j=0;j<face.getNNodes();j++){
				MeshNode node=face.getNode(j);
				if (!b3d.contains(node.x, node.y, node.z)){
					inside=false;
					break;
				}
			}
			if (!inside){
			newFaces.add(face);
			}
		}
		mesh.setFaces(newFaces);
		mesh.removeUnusedNodes();
	}

	public void implement(Mesh mesh, Box3D b3d, Mesh meshNew) {
		ArrayList<MeshNode> nodesInside = new ArrayList<MeshNode>();
		for (int i = 0; i < mesh.getNNodes(); i++) {
			MeshNode node = mesh.getNode(i);
			if (b3d.contains(node.x, node.y, node.z)) {
				nodesInside.add(node);
			}
		}
		if (nodesInside.size() > 0) {
			int hits = 0;
			for (int i = 0; i < meshNew.getNFaces(); i++) {
				MeshFace face = meshNew.getFace(i);
				for (int j = 0; j < face.getNNodes(); j++) {
					MeshNode node = face.getNode(j);
					for (int ii = 0; ii < nodesInside.size(); ii++) {
						MeshNode node2 = nodesInside.get(ii);
						if (node.equalPosition3D(node2, 0.01f)) {
							face.nodes[j] = node2;
							hits++;
						}
					}
				}
			}
			println("hits: " + hits);
			meshNew.removeUnusedNodes();
			for (int i = 0; i < meshNew.getNFaces(); i++) {
				MeshFace face = meshNew.getFace(i);
				mesh.addFace(face);
			}
			for (int i = 0; i < meshNew.getNNodes(); i++) {
				MeshNode node = meshNew.getNode(i);
				mesh.addNode(node);
			}
		}
	}
	
	public ArrayList<MeshNode> getCircle(float x,float y, float z, float radius,int nSegs){
		ArrayList<MeshNode> nodes=new ArrayList<MeshNode>();
		float dAngle=(float) (Math.PI*2f)/nSegs;
		for (int i=0;i<nSegs;i++){
			float cX=radius*(float)Math.cos(i*dAngle-0.75f*PI)+x;
			float cY=radius*(float)Math.sin(i*dAngle-0.75f*PI)+y;
			MeshNode node=new MeshNode(cX,cY,z);
			nodes.add(node);
		}
		return nodes;
	}
	public Mesh getConeWithPlate(float d,float dGrid,float r,float h){
		Mesh mesh=new Mesh();
		float x1=0;
		float y1=0;
		float x2=d;
		float y2=d;
		int nX=(int)((d)/dGrid);
		int nY=nX;
		ArrayList<MeshNode>outterRing=new ArrayList<MeshNode>();
		for (int i=0;i<nX;i++){
			float cX=x1+i*dGrid;
			float cY=y1;
			outterRing.add(new MeshNode(cX,cY,0));
		}
		for (int i=0;i<nY;i++){
			float cX=x2;
			float cY=y1+i*dGrid;
			outterRing.add(new MeshNode(cX,cY,0));
		}
		for (int i=0;i<nX;i++){
			float cX=x2-i*dGrid;
			float cY=y2;
			outterRing.add(new MeshNode(cX,cY,0));
		}
		for (int i=0;i<nY;i++){
			float cX=x1;
			float cY=y2-i*dGrid;
			outterRing.add(new MeshNode(cX,cY,0));
		}
		
		mesh.addNodes(outterRing);
		
		
		ArrayList<MeshNode>circle1=getCircle(d*0.5f,d*0.5f,0,r,outterRing.size());
		ArrayList<MeshNode>circle2=getCircle(d*0.5f,d*0.5f,h,r+coneOffset,outterRing.size());
		mesh.addNodes(circle1);
		mesh.addNodes(circle2);
		MeshNode center=new MeshNode(d*0.5f,d*0.5f,h);
		mesh.addNode(center);
		for (int i=0;i<outterRing.size();i++){
			MeshNode p1=outterRing.get(i);
			MeshNode p2=outterRing.get((i+1)%outterRing.size());
			MeshNode b1=circle1.get(i);
			MeshNode b2=circle1.get((i+1)%circle1.size());
			mesh.addTri(p1,p2,b1);
			mesh.addTri(b2,b1,p2);
		}
		for (int i=0;i<circle1.size();i++){
			MeshNode p1=circle1.get(i);
			MeshNode p2=circle1.get((i+1)%circle1.size());
			MeshNode b1=circle2.get(i);
			MeshNode b2=circle2.get((i+1)%circle1.size());
			mesh.addTri(p1,p2,b1);
			mesh.addTri(b2,b1,p2);
		}
		for (int i=0;i<circle2.size();i++){
			MeshNode p1=circle2.get(i);
			MeshNode p2=circle2.get((i+1)%circle1.size());
			mesh.addTri(p1,p2,center);
		}
		
		return mesh;
	}
}
	
